/**
 * 
 */
package com.feib.stms.action;

import it.sauronsoftware.base64.Base64;

import java.io.IOException;
import java.net.MalformedURLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.DontBind;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.integration.spring.SpringBean;
import net.sourceforge.stripes.validation.DateTypeConverter;
import net.sourceforge.stripes.validation.Validate;

import org.apache.commons.collections.CollectionUtils;

import org.apache.commons.lang.StringUtils;
import org.apache.xmlrpc.XmlRpcClient;
import org.apache.xmlrpc.XmlRpcException;

import org.springframework.context.support.ResourceBundleMessageSource;



import com.feib.stms.model.ConfirmRule;
import com.feib.stms.model.UploadFile;
import com.feib.stms.model.User;
import com.feib.stms.pagination.PaginatedList;
import com.feib.stms.service.ConfirmRuleService;
import com.feib.stms.service.UploadFileService;
import com.feib.stms.service.UserService;

import com.feib.stms.util.UserUtil;


/**
 * 
 * @title (#).java<br>
 * @description 上傳檔案 審查/放行/取消 公用Controller<br/>
 * <ul>
 * <li>需求說明: 使用者查詢/列印報表/下載驗資明細資料。</li>
 * <li>業務規則說明:
 * <ol>
 * <li>1.資料必須通過多人審查,放行(券商自定門檻人數)，才算審查完畢</li>
 * <li>2.同一份資料，同一主管不能執行審查作業又執行放行作業。
 * <br/>也就是審查主管與放行主管不可為同一人；且此主管最多只能審查一次or放行一次此交割款資料。</li>
 * </ol></li>
 * <li>業務規則說明:
 * <ol>
 * <li>1.已通過放行門檻人數、且系統尚未執行預約扣款的xxx資料，才可以執行取消作業。
 * <li>2.取消作業意指系統已不處理此xxx資料。
 * <li>3.放行者才有權限取消該筆資料。
 * </ol></li>
 * <li>使用單位及角色:
 * <ol>
 * <li>券商端。</li>
 * </ol></li>
 * <li>例外狀況處理:
 * <ol>
 * <li>1.xxx資料已預約扣款:系統顯示"xxx資料已預約扣款，無法取消"錯誤訊息
 * <li>2.因網路等問題無法取消檔案:系統顯示"因連線問題，xxx資料無法取消"錯誤訊息。
 * </ol></li> 
 * </ul>
 * @author Jeff Gu
 * @version 1.0.0 2012/06/05
 * @copyright Far Eastern International Bank Copyright (c) 2012<br>
 * 
 */
public abstract class BaseDoUploadFileActionbean extends BaseActionBean  {

	/**
	 * 起始頁<br/>
	 * EX:stms2003.jsp
	 * @return
	 */
	protected abstract String getDefaultPage();

	/**
	 * 上傳檔案類型
	 * 目前一個功能只會出現一種類型<br/>
	 * @return
	 */
	public abstract String getUploadFileFormat();

	/**
	 * 上傳檔案狀態
	 * @return
	 */
	public abstract List<Integer> getFileStatus();

	/**
	 * 下載明細檔名
	 * @return
	 */
	public abstract String getDownloadFileName();

	/**
	 * 待辦事項目錄 
	 * 要加入的是下一步驟的MenuItemPk,請由UploadFileTodoList中取得
	 * @return
	 */
	public abstract Long getTodoListMenuItemPk();

	/**
	 * 檔案操作紀錄類型 用來查詢現在檔案的處理狀況是否已經達到處理門檻
	 * @return
	 */
	public abstract List<String> getActions();


	/**
	 * 刪除檔案狀態
	 * 50: 已刪除/不放行(只要有一人不放行，即為放行不通過；明細應註記為刪除)
	 * 20: 已刪除/審查不通過(只要有一人審查不通過，即為審查不通過；明細應註記為刪除)
	 * @return
	 */
	public abstract Integer getDeleteStatus();

	protected DateFormat yyyyMMddHHmmSS = new SimpleDateFormat("yyyyMMddHHmmSS");


	@SpringBean("messageSource")
	protected ResourceBundleMessageSource messageSource;

	@SpringBean("uploadFileService")
	private UploadFileService uploadFileService;

	@SpringBean("confirmRuleService")
	private ConfirmRuleService confirmRuleService;

	@SpringBean("userService")
	private  UserService userService;

	/**
	 * 查詢條件-檔案類型 
	 */
	protected List<String> fileFormats;

	/**
	 * 查詢條件-交割日期迄
	 */
	@Validate( converter=DateTypeConverter.class)
	protected Date qryDeliveryDateFrom;

	/**
	 * 查詢條件-交割日期迄
	 */
	@Validate( converter=DateTypeConverter.class)
	protected Date qryDeliveryDateTo;

	/**
	 * 查詢條件
	 */
	private UploadFile qryUploadFile;

	/**
	 * 查詢條件-檔案類型 
	 */
	protected List<Integer> fileStatus;

	/**
	 * 查詢條件-分公司代號
	 */
	private List<String> qrySecuritiesNos;

	/**
	 * 查詢條件-只能查詢分公司的代號，系統控制(從user取得)
	 */
	private List<String> userDealSecuritiesNos;



	/**
	 * 檔案查詢結果(多筆)
	 */
	private PaginatedList<UploadFile> queryResult;

	/**
	 * 畫面選擇處理檔案(多筆)
	 */
	private ArrayList<UploadFile> checkUploadFiles;

	/**
	 * 設定查詢action_log的 action 
	 */
	protected List<String> actions;

	/**
	 * 設定待辦事項的 action 
	 */
	protected  Long  todoListMenuItemPk;

	/**
	 * 設定刪除檔案狀態
	 * 50: 已刪除/不放行(只要有一人不放行，即為放行不通過；明細應註記為刪除)
	 * 20: 已刪除/審查不通過(只要有一人審查不通過，即為審查不通過；明細應註記為刪除)
	 */
	protected  Integer  deleteFileStatus;

	/**
	 * 訊息-畫面顯示用
	 */
	private String message;

	/**
	 * 錯誤訊息-畫面顯示用
	 */
	private String errorMessage;

	/**
	 * 畫面選擇的刪除檔案pk
	 */
	private Long deleteUploadFilePk;

	/**
	 * 券商流程--判斷放行認證方式
	 */
	private ConfirmRule  fileConfirmRule;

	/**
	 * 檔案md5值
	 */
	private String md5Data;

	/**
	 * 使用者設定的憑證
	 */
	private String serverCN;

	/**
	 * IKEY產生的憑證
	 */
	private String clientCN;


	/**
	 * frm.signerCert.value = CertDBClientObj.certificate;	
	 */
	private String signerCert;


	protected static Map<String, String> SORT_DETAIL_FIELD_NAMES = new LinkedHashMap<String, String>();
	static{


		//交割帳號
		SORT_DETAIL_FIELD_NAMES.put("deliveryDate", "DELIVERY_DATE"); // 交割日期或扣帳日期
		SORT_DETAIL_FIELD_NAMES.put("accountNo", "ACCOUNT_NO"); // 存款帳號
		SORT_DETAIL_FIELD_NAMES.put("accountNoChk", "ACCOUNT_NO_CHK"); // 帳號檢查碼
		SORT_DETAIL_FIELD_NAMES.put("amountChk", "AMOUNT_CHK"); // 金額檢查碼

		SORT_DETAIL_FIELD_NAMES.put("dealType", "DEAL_TYPE"); // 處理類別
		SORT_DETAIL_FIELD_NAMES.put("customerName", "CUSTOMER_NAME"); // 客戶戶名
		SORT_DETAIL_FIELD_NAMES.put("stockNo", "STOCK_NO"); // 證券代號
		SORT_DETAIL_FIELD_NAMES.put("stockName", "STOCK_NAME"); // 證券名稱

		SORT_DETAIL_FIELD_NAMES.put("chargebackPriority", "CHARGEBACK_PRIORITY"); // 扣款優先種類
		SORT_DETAIL_FIELD_NAMES.put("chargebackPriorityCode", "CHARGEBACK_PRIORITY_CODE"); // 扣款先後序號
		SORT_DETAIL_FIELD_NAMES.put("teller", "TELLER"); // 營業櫃員
		SORT_DETAIL_FIELD_NAMES.put("dealResultCode", "DEAL_RESULT_CODE"); // 處理狀況代號
		SORT_DETAIL_FIELD_NAMES.put("customerId", "CUSTOMER_ID"); // 身份證號
		SORT_DETAIL_FIELD_NAMES.put("securitiesNo", "SECURITIES_NO"); // 券商代號
	}


	protected static Map<String, String> SORT_FIELD_NAMES = new LinkedHashMap<String, String>();
	static{

		//放行清單畫面
		SORT_FIELD_NAMES.put("fileName", "FILE_NAME");//放行資料
		SORT_FIELD_NAMES.put("fileFormatName", "FILE_FORMAT_NAME");//檔案名稱
		SORT_FIELD_NAMES.put("totalNetIncomeCount", "TOTAL_NET_INCOME_COUNT");//淨收筆數
		SORT_FIELD_NAMES.put("netIncome", "NET_INCOME"); // 淨收金額
		SORT_FIELD_NAMES.put("totalNetPayCount", "TOTAL_NET_PAY_COUNT");//淨付筆數
		SORT_FIELD_NAMES.put("netPay", "NET_PAY"); // 淨付金額
		SORT_FIELD_NAMES.put("chksum", "CHKSUM");//總檢核數
		SORT_FIELD_NAMES.put("deliveryAccount", "DELIVERY_ACCOUNT");//交割帳號(來自券商約定帳號)
	}


	/**
	 * 預設頁面,審查頁面直接顯示待審查資料
	 */
	private static final String PKI_JSP = "/WEB-INF/pki.jsp";




	@DontBind
	@DefaultHandler
	public Resolution doDefault()
	{
		logger.debug("Enter doDefault mehtod.");
		return doQuery();
	}


	/**
	 * 檔案排序使用(非明細)
	 * @param qryCondition
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	protected void setQueryCondition(PaginatedList<UploadFile> qryCondition) throws InstantiationException, IllegalAccessException
	{
		logger.debug("Enter setQueryCondition(UploadFile) mehtod.");

		/* 設定換頁、排序等條件*/
		String sortCriterion = null == queryResult ? null : queryResult.getSortCriterion();
		List<String> sortFields = getSortFields();
		if (StringUtils.isEmpty(sortCriterion) || null == getSortFieldNames().get(sortCriterion)) // 未設定/找不到 排序條件時候，則以存款帳號為主要排序
			sortCriterion = sortFields.get(0);


		if (null != queryResult)
		{
			qryCondition.setPageNumber(queryResult.getPageNumber());
			qryCondition.setPageSize(queryResult.getPageSize());
			qryCondition.setSortCriterion(getSortFieldNames().get(sortCriterion));
			qryCondition.setSortDirection(queryResult.getSortDirection());
		}


		if (null == queryResult || StringUtils.isEmpty(queryResult.getSortCriterion()) || !sortFields.contains(queryResult.getSortCriterion()))
		{
			// 以存款帳號由大到小排序
			qryCondition.setSortCriterion(getSortFieldNames().get(sortFields.get(0)));
			qryCondition.setSortDirection(PaginatedList.SORT_DIRECTION_DESC);
		}






	}
	/**
	 * 查詢上傳檔案
	 * @return
	 */
	public Resolution doQuery()
	{
		logger.debug("Enter doQuery mehtod.");
		try {

			String sortCriterion = null == queryResult ? null : queryResult.getSortCriterion();
			List<String> sortFields = getSortFields();
			if (StringUtils.isEmpty(sortCriterion) || null == getSortFieldNames().get(sortCriterion)) // 未設定/找不到 排序條件時候，則以存款帳號為主要排序
				sortCriterion = sortFields.get(0);

			PaginatedList<UploadFile> qryCondition = new PaginatedList<UploadFile>();
			setQueryCondition(qryCondition);

			if (null == qryUploadFile)
				qryUploadFile = new UploadFile();		
			/* 設定user可以查詢的 券商代號 */
			qryUploadFile.setUploadUser(new User());
			qryUploadFile.getUploadUser().setDealSecuritiesNos(UserUtil.getUser().getDealSecuritiesNos());
			/* 設定user pk 判斷是否可以對檔案作操作 */
			qryUploadFile.getUploadUser().setUserPk(UserUtil.getUser().getUserPk());
			qryUploadFile.setGroup(UserUtil.getUserGroup());
			qryUploadFile.setFileFormat(getUploadFileFormat());
			this.queryResult=uploadFileService.findPaginatedListDealUploadFile(qryUploadFile, this.qryDeliveryDateFrom, this.qryDeliveryDateTo, fileFormats, fileStatus, qryCondition);


			if (null == queryResult)
			{
				if(StringUtils.isNotEmpty(this.message)){
					this.message=this.message+"</br>";
				}else{
					this.message="";
				}
				//this.message =this.message+messageSource.getMessage("query.nothing", null, "查無資料！", this.getContext().getRequest().getLocale());
				queryResult = new PaginatedList<UploadFile>(); 
				queryResult.setPageNumber(qryCondition.getPageNumber());
				queryResult.setPageSize(qryCondition.getPageSize());
			}

			this.queryResult.setSortCriterion(sortCriterion);
			this.queryResult.setSortDirection(qryCondition.getSortDirection());

		} catch (Exception e) {
			logger.error("查詢發生錯誤:",e);
		}



		return new ForwardResolution(getDefaultPage());
	}




	/**
	 * 檔案審查作業
	 * @return
	 */
	public Resolution  doCheck(){

		logger.debug("Enter doCheck mehtod.");

		try {
			uploadFileService.doCheckUploadFile(checkUploadFiles,todoListMenuItemPk ,actions);
			this.message = messageSource.getMessage("upload.file.check", null, "審查成功！", this.getContext().getRequest().getLocale());			
		} catch (Exception e) {
			logger.error("審查發生錯誤:",e);
			this.errorMessage= messageSource.getMessage("upload.file.check.error", null, "審查失敗！", this.getContext().getRequest().getLocale());
		}

		return doQuery();

	}


	/**
	 * 檔案放行作業
	 * @return
	 */
	public Resolution  doConfirm(){

		logger.debug("Enter doConfirm mehtod.");

		try {
			uploadFileService.doConfirmUploadFile(checkUploadFiles, actions, signerCert);
			this.message = messageSource.getMessage("upload.file.confiirm", null, "放行成功！", this.getContext().getRequest().getLocale());

		} catch (Exception e) {
			logger.error("放行發生錯誤:",e);
			this.errorMessage= messageSource.getMessage("upload.file.confiirm.error", null, "放行失敗！", this.getContext().getRequest().getLocale());
		}

		return doQuery();

	}

	/**
	 * 檔案取消作業
	 * @return
	 */
	public Resolution  doCancel(){

		logger.debug("Enter doCancel mehtod.");

		try {
			uploadFileService.doCancelUploadFile(checkUploadFiles);
			this.message = messageSource.getMessage("upload.file.doCancel", null, "取消成功！", this.getContext().getRequest().getLocale());

		} catch (Exception e) {
			logger.error("取消發生錯誤:",e);
			this.errorMessage= messageSource.getMessage("upload.file.doCancel.error", null, "取消失敗！", this.getContext().getRequest().getLocale());
		}

		return doQuery();

	}


	/**
	 * 檔案刪除作業-單筆
	 * @return
	 */
	public Resolution  doDelete(){

		logger.debug("Enter doDelete mehtod.");

		try {
			logger.debug("deleteUploadFilePk {},deleteFileStatus{}",deleteUploadFilePk, deleteFileStatus);
			if(0==uploadFileService.doDeleteUploadFile(deleteUploadFilePk, deleteFileStatus)){
				this.errorMessage= messageSource.getMessage("upload.file.doDelete.error", null, "刪除失敗！", this.getContext().getRequest().getLocale());
			}

			this.message = messageSource.getMessage("upload.file.doDelete", null, "刪除成功！", this.getContext().getRequest().getLocale());

		} catch (Exception e) {
			logger.error("刪除發生錯誤:",e);
			this.errorMessage= messageSource.getMessage("upload.file.doDelete.error", null, "刪除失敗！", this.getContext().getRequest().getLocale());
		}

		return doQuery();

	}


	/**
	 * 放行認證
	 * @return
	 */
	public Resolution doPki(){

		logger.debug("Enter doPki mehtod.");

		/*取得券商流程--判斷放行認證方式*/
		fileConfirmRule=confirmRuleService.findConfirmRuleEnabled(UserUtil.getUserGroup());
		md5Data="";
		if(0==fileConfirmRule.getConfirmType()){
			/* 放行認證方式 帳號密碼 不用驗證 */
			return	doConfirm();
		}else{	
			for (UploadFile uf:checkUploadFiles){
				String md5=uf.getFileMd5();				
				if(StringUtils.isNotEmpty(md5)){
					md5Data+=md5+",";
				}	
			}
			md5Data=md5Data.substring(0, md5Data.length()-1).trim();/* 檔案MD5值,多個用,隔開 */
			User user=UserUtil.getUser();
			serverCN=userService.findByUerPk(user.getUserPk()).getCertificateKey();/* 簽章 */

		}
		return new ForwardResolution(PKI_JSP);

	}	




	/**
	 * 放行認證
	 * @return
	 */
	public Resolution doVerify(){

		logger.debug("Enter doVerify mehtod.");


		try {	
			/* 請系統參數化、正式套測試URL不同 TODO*/
			String strURL = "http://10.48.16.8:3799";

			XmlRpcClient oClint = new XmlRpcClient(strURL);

			Vector oParams = new Vector();
			oParams.addElement(signerCert);							
			String strEcode = (String) oClint.execute("vc.Vertify",oParams);
			
			if (Base64.decode(strEcode).equals("OK")){

			}else{
				this.errorMessage="驗章失敗";
				return doQuery();
			}	  

		} catch (MalformedURLException emf) {			
			logger.error("MalformedURLException : {}",emf.toString());
			this.errorMessage="驗章失敗";
			return doQuery();
		} catch (XmlRpcException e) {  
			logger.error("XmlRpcException : {}",e.toString());
			this.errorMessage="驗章失敗";
			return doQuery();
		} catch (IOException e) {		
			logger.error("IOException : {}",e.toString());
			this.errorMessage="驗章失敗";
			return doQuery();
		}

		return	doConfirm(); 

	}







	public List<String> getSortFields()
	{
		List<String> result = new ArrayList<String>();
		CollectionUtils.addAll(result, getSortFieldNames().keySet().iterator()	);
		return result;
	}

	public List<String> getSortDetailFields()
	{
		List<String> result = new ArrayList<String>();
		CollectionUtils.addAll(result, getSortDetailFieldNames().keySet().iterator()	);
		return result;
	}


	public void setNavigator()
	{
		if (null != queryResult)
		{
			int sortDirection = queryResult.getSortDirection();  //2 : ascending, else: descending
			String sortSpan = "<span class=\"ui-icon ui-icon-circle-triangle-n\"></span>"; //由小到大
			if (1 == sortDirection)
			{
				sortSpan = "<span class=\"ui-icon ui-icon-circle-triangle-s\"></span>"; //由大到小
			}

			String sortCriterion = queryResult.getSortCriterion();
			if (null!= sortCriterion && null != getSortFieldNames().get(sortCriterion))
			{
				this.getContext().getRequest().setAttribute(sortCriterion+"SortedClass", 1==sortDirection?"sortDesc":"sortAsc");
				this.getContext().getRequest().setAttribute(sortCriterion+"SortedSpan", sortSpan);
			}
			else
			{
				sortCriterion = getSortFields().get(0);
				this.getContext().getRequest().setAttribute(sortCriterion+"SortedClass", 1==sortDirection?"sortDesc":"sortAsc");
				this.getContext().getRequest().setAttribute(sortCriterion+"SortedSpan", sortSpan);
			}


			// 上下頁鈕處理
			int lastPageNumber = queryResult.getTotalPageCount();
			int currentPageNumber = queryResult.getPageNumber();
			int prePageNumber = currentPageNumber - 1;
			int nextPageNumber = currentPageNumber + 1;

			this.getContext().getRequest().setAttribute("lastPageNumber", new Integer(lastPageNumber));
			this.getContext().getRequest().setAttribute("currentPageNumber", new Integer(currentPageNumber));
			this.getContext().getRequest().setAttribute("prePageNumber", new Integer(prePageNumber));
			this.getContext().getRequest().setAttribute("nextPageNumber", new Integer(nextPageNumber));
		}
	}



	protected Map<String, String> getSortFieldNames(){
		return SORT_FIELD_NAMES;
	}

	protected Map<String, String> getSortDetailFieldNames(){
		return SORT_DETAIL_FIELD_NAMES;
	}



	/**
	 * @param qrySecuritiesNos 的設定的 qrySecuritiesNos
	 */
	public void setQrySecuritiesNos(List<String> qrySecuritiesNos) {
		this.qrySecuritiesNos = qrySecuritiesNos;
	}

	/**
	 * @return qrySecuritiesNos
	 */
	public List<String> getQrySecuritiesNos() {
		return qrySecuritiesNos;
	}

	/**
	 * @param userDealSecuritiesNos 的設定的 userDealSecuritiesNos
	 */
	public void setUserDealSecuritiesNos(List<String> userDealSecuritiesNos) {
		this.userDealSecuritiesNos = userDealSecuritiesNos;
	}

	/**
	 * @return userDealSecuritiesNos
	 */
	public List<String> getUserDealSecuritiesNos() {
		return userDealSecuritiesNos;
	}


	/**
	 * @param message 的設定的 message
	 */
	public void setMessage(String message) {
		this.message = message;
	}

	/**
	 * @return message
	 */
	public String getMessage() {
		return message;
	}

	/**
	 * @param errorMessage 的設定的 errorMessage
	 */
	public void setErrorMessage(String errorMessage) {
		this.errorMessage = errorMessage;
	}

	/**
	 * @return errorMessage
	 */
	public String getErrorMessage() {
		return errorMessage;
	}

	/**
	 * @param queryResult 的設定的 queryResult
	 */
	public void setQueryResult(PaginatedList<UploadFile> queryResult) {
		this.queryResult = queryResult;
	}

	/**
	 * @return queryResult
	 */
	public PaginatedList<UploadFile> getQueryResult() {
		return queryResult;
	}

	/**
	 * @param qryUploadFile 的設定的 qryUploadFile
	 */
	public void setQryUploadFile(UploadFile qryUploadFileContent) {
		this.qryUploadFile = qryUploadFileContent;
	}

	/**
	 * @return qryUploadFile
	 */
	public UploadFile getQryUploadFile() {
		return qryUploadFile;
	}


	public Date getQryDeliveryDateFrom() {
		return qryDeliveryDateFrom;
	}

	public void setQryDeliveryDateFrom(Date qryDeliveryDateFrom) {
		this.qryDeliveryDateFrom = qryDeliveryDateFrom;
	}

	public Date getQryDeliveryDateTo() {
		return qryDeliveryDateTo;
	}

	public void setQryDeliveryDateTo(Date qryDeliveryDateTo) {
		this.qryDeliveryDateTo = qryDeliveryDateTo;
	}

	public void setCheckUploadFiles(ArrayList<UploadFile> checkUploadFiles) {
		this.checkUploadFiles = checkUploadFiles;
	}

	public ArrayList<UploadFile> getCheckUploadFiles() {
		return checkUploadFiles;
	}

	public void setDeleteUploadFilePk(Long deleteUploadFilePk) {
		this.deleteUploadFilePk = deleteUploadFilePk;
	}

	public Long getDeleteUploadFilePk() {
		return deleteUploadFilePk;
	}

	/**
	 * @param fileConfirmRule 的設定的 fileConfirmRule
	 */
	public void setFileConfirmRule(ConfirmRule fileConfirmRule) {
		this.fileConfirmRule = fileConfirmRule;
	}

	/**
	 * @return fileConfirmRule
	 */
	public ConfirmRule getFileConfirmRule() {
		return fileConfirmRule;
	}

	public String getMd5Data() {
		return md5Data;
	}

	public void setMd5Data(String md5Data) {
		this.md5Data = md5Data;
	}

	public String getServerCN() {
		return serverCN;
	}

	public void setServerCN(String serverCn) {
		this.serverCN = serverCn;
	}

	/**
	 * @param clientCN 的設定的 clientCN
	 */
	public void setClientCN(String clientCN) {
		this.clientCN = clientCN;
	}

	/**
	 * @return clientCN
	 */
	public String getClientCN() {
		return clientCN;
	}

	/**
	 * @param signerCert 的設定的 signerCert
	 */
	public void setSignerCert(String signerCert) {
		this.signerCert = signerCert;
	}

	/**
	 * @return signerCert
	 */
	public String getSignerCert() {
		return signerCert;
	}

}
